const MyPromise = (() => {
  const PENDING = "pending",
    RESOLVED = "resolved",
    REJECTED = "rejected",
    PromiseValue = Symbol("PromiseValue"),
    PromiseStatus = Symbol("PromiseStatus"), //状态数据
    thenables = Symbol("thenables"), //thenables
    catchables = Symbol("catchbles"), //catchables
    changeStatus = Symbol("changeStatus"), //当前状态
    settleHandle = Symbol("settleHandle"), //后续处理的通用函数
    linkPromise = Symbol("linkPromise"); //创建串联的Promise

  return class MyPromise {
    /**
     * 改变当前Promise的状态
     * @param {*} newStatus
     * @param {*} newValue
     * @param {*} queue 执行的作业队列
     */
    [changeStatus] (newStatus, newValue, queue) {
      // 改变状态方法，该方法是通过外部手动书写resolve()/reject()触发的
      if (this[PromiseStatus] !== PENDING) {
        //状态无法变更
        return;
      }
      // this[PromiseStatus] === PENDING 为true时的状态执行下面的代码
      this[PromiseStatus] = newStatus;
      this[PromiseValue] = newValue;
      // 执行相应队列中的函数
      // 该queue队列并不是链式调用then后产生的链式掉用函数，而是在new Promise后的第一个，同级别的一大堆then的事件处理函数
      queue.forEach((handler) => handler(newValue));
    }

    /**
     *
     * @param {*} executor 未决阶段（pending状态）下的处理函数
     */
    constructor(executor) {
      // 其中executor为new Promise((resolve, reject) => {resolve(1)})中的(resolve, reject) => {resolve(1)}
      this[PromiseStatus] = PENDING;
      this[PromiseValue] = undefined;
      this[thenables] = []; //后续处理函数的数组 -> resolved
      this[catchables] = []; //后续处理函数的数组 -> rejected

      const resolve = (data) => {
        // 使用箭头函数是为了解决this指向问题，这个resolve函数是在(resolve, reject) => {resolve(1)}中被window调用的，所以使用function会导致this指向出问题
        // data为new Promise((resolve, reject) => {resolve(1)})中里resolve(1)的1
        this[changeStatus](RESOLVED, data, this[thenables]);
      };

      const reject = (reason) => {
        this[changeStatus](REJECTED, reason, this[catchables]);
      };
      try {
        // 把resolve和reject函数传入到executor里，此时executor函数为 new Promise((resolve, reject) => {resolve(1)})中的未决状态函数 (resolve, reject) => {resolve(1)}
        executor(resolve, reject);
      } catch (err) {
        // 处理在 new Promise中出现throw new Error的情况
        reject(err);
      }
    }

    /**
     * 处理 后续处理函数
     * @param {*} handler 后续处理函数
     * @param {*} immediatelyStatus 需要立即执行的状态
     * @param {*} queue 作业队列
     */
    [settleHandle](handler, immediatelyStatus, queue) {
      // handler为后续处理函数
      if (typeof handler !== "function") {
        return;
      }
      if (this[PromiseStatus] === immediatelyStatus) {
        // 如果到达立即执行状态则直接运行
        setTimeout(() => {
          handler(this[PromiseValue]);
        }, 0);
      } else {
        // 否则加入事件队列
        queue.push(handler);
      }
    }

    [linkPromise](thenalbe, catchable) {
      // 在传入参数时thenalbe, catchable都有可能是undefined，因为对promise的以决状态可以不做后续处理（这种情况下会把该已决状态的数据一直向下抛，直到有该状态处理函数的地方），所以要特殊处理undefined的情况
      function exec(data, handler, resolve, reject) {
        // 这里面的data为[settleHandle](handler, immediatelyStatus, queue)中的handler(this[PromiseValue])里的this[PromiseValue]
        try {
          const result = handler(data); //得到当前Promise的处理结果
          if (result instanceof MyPromise) {
            result.then(
              (d) => {
                resolve(d);
              },
              (err) => {
                reject(err);
              }
            );
          } else {
            resolve(result);
          }
        } catch (err) {
          reject(err);
        }
      }

      return new MyPromise((resolve, reject) => {
        // 设置RESOLVED后续处理函数
        this[settleHandle](
          (data) => {
            if (typeof thenable !== "function") {
              // 父级promise没有注册thenable的情况
              resolve(data); // 就自己处理
              return;
            }
            exec(data, thenalbe, resolve, reject);
          },
          RESOLVED,
          this[thenables]
        );
        // 设置REJECTED后续处理函数
        this[settleHandle](
          (reason) => {
            if (typeof catchable !== "function") {
              // 父级promise没有注册catchable的情况
              reject(reason); // 就自己处理
              return;
            }
            exec(reason, catchable, resolve, reject);
          },
          REJECTED,
          this[catchables]
        );
      });
    }

    then(thenable, catchable) {
      // 正常应该是这样写的
      // this[settleHandle](thenable, RESOLVED, this[thenables]);
      // this.catch(catchable);
      return this[linkPromise](thenable, catchable);
    }

    catch(catchable) {
      // this[settleHandle](catchable, REJECTED, this[catchables]);
      return this[linkPromise](undefined, catchable);
    }

    static all(proms) {
      return new MyPromise((resolve, reject) => {
        const results = proms.map((p) => {
          const obj = {
            result: undefined,
            isResolved: false,
          };
          p.then(
            (data) => {
              obj.result = data;
              obj.isResolved = true;
              //判断是否所有的全部完成
              const unResolved = results.filter((r) => !r.isResolved);
              if (unResolved.length === 0) {
                //全部完成
                resolve(results.map((r) => r.result));
              }
            },
            (reason) => {
              reject(reason);
            }
          );
          return obj;
        });
      });
    }

    static race(proms) {
      return new MyPromise((resolve, reject) => {
        proms.forEach((p) => {
          p.then(
            (data) => {
              resolve(data);
            },
            (err) => {
              reject(err);
            }
          );
        });
      });
    }

    static resolve(data) {
      if (data instanceof MyPromise) {
        return data;
      } else {
        return new MyPromise((resolve) => {
          resolve(data);
        });
      }
    }

    static reject(reason) {
      return new MyPromise((resolve, reject) => {
        reject(reason);
      });
    }
  };
})();
